<?php
/**
 * Place holder class
 * This class provides a way to store and retrieve information by key.
 *
 * @package OWL
 * @subpackage Core
 * @author KeiMOon
 * @since 1.5
 */

if (!defined("SINGLE_CONTENT")) {
    define ("SINGLE_CONTENT",0);
}

if (!defined("LOOP_CONTENT")) {
    define ("LOOP_CONTENT",1);
}

 class Owl_Place_Holder {
     /**
      * Place holder array
      *
      * @access private
      * @var array
      */
     private $place_holder;

     /**
      * Stack of current position in the loop
      *
      * @access private
      * @var Stack
      */
     private $current_stack;

     /**
      * Stack of content size
      *
      * @access private
      * @var Stack
      */
     private $size_stack;

     /**
      * The stack of key is being looped
      *
      * @access private
      * @var Stack
      */
     private $key_stack;

     /**
      * The root reference stack
      *
      * @access private
      * @var Reference stack
      */
     private $root_ref_stack;

     /**
      * PHP5 Constructor
      */
     function __construct() {
         $this->Owl_Place_Holder();
     }

     /**
      * PHP4 Constructor
      */
     function Owl_Place_Holder() {
         register_shutdown_function(array(@$this,"__destruct"));
         $this->place_holder = array();
         $this->key_stack = array(false);
         $this->current_stack = array();
         $this->size_stack = array();
         $this->root_ref_stack = array(&$this->place_holder);
     }

     /**
      * Destructor
      *
      * @return false 
      */
     function  __destruct() {
         return false;
     }

     /**
      * Assign value to a single content key
      *
      * @param string $key_string The key string
      * @param string $value The value
      *
      * @return bool False if the key is not a single key
      */
     function assign($key_string, $value) {
         $root_ref = & $this->root_ref_stack[count($this->root_ref_stack) - 1];
         if (!isset($root_ref[$key_string]) || $root_ref[$key_string]["type"] == SINGLE_CONTENT) {
             $root_ref[$key_string]["type"] = SINGLE_CONTENT;
             $root_ref[$key_string]["value"] = $value;
             return true;
         }
         else {
             return false;
         }
     }

     /**
      * Assign value to an array of  key
      *
      * @param array $array_var 
      *
      * @return bool False if the key is not a single key
      */
     function assign_array($array_var) {
        foreach ($array_var as $key=>$value) {
            if (!$this->assign($key, $value)) {
                return false;
            }
        }
        return true;
     }

     /**
      * Generate the single content of a key
      *
      * @param string $key The key
      */
     function put($key_string) {
         $root_ref = & $this->root_ref_stack[count($this->root_ref_stack) - 1];
         if ($root_ref[$key_string]["type"] == SINGLE_CONTENT) {
            echo $root_ref[$key_string]["value"];
         }
     }

     /**
      * Get the single content of a key
      *
      * @param string $key The key
      */
     function get($key_string) {
         $root_ref = & $this->root_ref_stack[count($this->root_ref_stack) - 1];
         if ($root_ref[$key_string]["type"] == SINGLE_CONTENT) {
            return $root_ref[$key_string]["value"];
         }
     }

     /**
      * Assign value to a loop content key
      *
      * @param string $key The key
      * @param Array/String $array_vars Array of value, in the form of
      * [key]=>[value], for example ["real_name"]=>"Foo",
      * ["nice_name"]=>"Bar", ["Age"]=>"17"
      *
      * @return bool False if the key is not a loop key
      */
     function assign_loop($key, $array_vars) {
         $root_ref = & $this->root_ref_stack[count($this->root_ref_stack) - 1];
         if(!isset($root_ref[$key]) || $root_ref[$key]["type"] == LOOP_CONTENT) {
             $root_ref[$key]["type"] = LOOP_CONTENT;
             $root_ref[$key]["size"] = count($root_ref[$key]["value"]);
             $to_assign = array();
             foreach ($array_vars as $key_var => $value) {
                 $to_assign[$key_var]["type"] = SINGLE_CONTENT;
                 $to_assign[$key_var]["value"] = $value;
             }
             
             $root_ref[$key]["value"][$root_ref[$key]["size"]] = $to_assign;
             $root_ref[$key]["size"] ++ ;
             return true;
         }
         else {
             return false;
         }
     }

     /**
      * Loop function. Check if the loop is available or not. Use this function 
      * with while loop. 
      * 
      * @param string $key The key contains the loop contents
      * @return bool true if loopable
      */
     function loop($key) {
         if (end($this->key_stack) != $key) { //Loop begin
             $root_ref = & $this->root_ref_stack[count($this->root_ref_stack) - 1];
             if (empty($root_ref[$key]) || $root_ref[$key]["type"] != LOOP_CONTENT) {
                 return false;
             }
             else {
                 array_push($this->key_stack, $key);
                 array_push($this->current_stack, 0);
                 array_push($this->size_stack, $root_ref[$key]["size"]);
                 array_push($this->root_ref_stack, & $root_ref[$key]["value"][end($this->current_stack)]);
                 return true;
             }
         }
         elseif (end($this->current_stack) < end($this->size_stack) - 1) {
             $this->current_stack[count($this->current_stack) - 1]++;
             $this->root_ref_stack[count($this->root_ref_stack) - 1] = & $this->root_ref_stack[count($this->root_ref_stack) - 2][$key]["value"][end($this->current_stack)];
             return true;
         }
         else {
             array_pop($this->key_stack);
             array_pop($this->current_stack);
             array_pop($this->size_stack);
             array_pop($this->root_ref_stack);
             return false;
         }
     }
     
 }

 //API

 /**
  * Assign value to a content key
  *
  * @param string $key The key
  * @param string $value The value
  */
 function assign($key_string, $value) {
     global $place_holder_control;
     return $place_holder_control->assign($key_string, $value);
 }

 /**
  * Assign value to an array of  key
  *
  * @param array $array_var
  *
  * @return bool False if the key is not a single key
  */
 function assign_array($array_var) {
     global $place_holder_control;
     return $place_holder_control->assign_array($array_var);
 }

 /**
  * Generate the content of a key
  *
  * @param <type> $key The key
  */
 function put($key_string) {
     global $place_holder_control;
     return $place_holder_control->put($key_string);
 }

  /**
  * Get the content of a key
  *
  * @param <type> $key The key
  */
 function get($key_string) {
     global $place_holder_control;
     return $place_holder_control->get($key_string);
 }

 /**
  * Assign value to a loop content key
  *
  * @param string $key The key
  * @param Array/String $array_vars Array of value, in the form of
  * [path]=>[value], for example ["name.real_name"]=>"Foo",
  * ["name.nice_name"]=>"Bar", ["Age"]=>"17"
  *
  * @return bool False if the key is not a loop key
  */
 function assign_loop($key, $array_vars) {
     global $place_holder_control;
     return $place_holder_control->assign_loop($key, $array_vars);
 }

  /**
  * Loop function. Check if the loop is available or not. Use this function
  * with while loop.
  *
  * @param string $key The key contains the loop contents
  * @return bool true if loopable
  */
 function loop($key) {
    global $place_holder_control;
    return $place_holder_control->loop($key);
 }


